<?php
// +----------------------------------------------------------------------
// | OneThink [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: huajie <banhuajie@163.com>
// +----------------------------------------------------------------------
namespace Admin\Controller;

use OT\File;

/**
 * 在线更新
 * 
 * @author huajie <banhuajie@163.com>
 */
class UpdateController extends AdminController {
	
	/**
	 * 初始化页面
	 * 
	 * @author huajie <banhuajie@163.com>
	 */
	public function index() {
		$this->meta_title = '在线更新';
		if (IS_POST) {
			$this->display ();
			// 检查新版本
			$version = $this->checkVersion ();
			// 在线更新
			$this->update ( $version );
		} else {
			$this->display ();
		}
	}
	
	/**
	 * 检查新版本
	 * 
	 * @author huajie <banhuajie@163.com>
	 */
	private function checkVersion() {
		if (extension_loaded ( 'curl' )) {
			$url = 'http://www.onethink.cn/index.php?m=home&c=check_version';
			$params = array (
					'version' => ONETHINK_VERSION,
					'domain' => $_SERVER ['HTTP_HOST'],
					'auth' => sha1 ( C ( 'DATA_AUTH_KEY' ) ) 
			);
			$vars = http_build_query ( $params );
			// 获取版本数据
			$data = $this->getRemoteUrl ( $url, 'post', $vars );
			if (! empty ( $data ) && strlen ( $data ) < 400) {
				$this->showMsg ( '发现新版本：' . $data, 'success' );
				return $data;
			} else {
				$this->showMsg ( "未发现新版本", 'error' );
				exit ();
			}
		} else {
			$this->error ( '请配置支持curl' );
		}
	}
	
	/**
	 * 在线更新
	 * 
	 * @author huajie <banhuajie@163.com>
	 */
	private function update($version) {
		// PclZip类库不支持命名空间
		import ( 'OT/PclZip' );
		
		$date = date ( 'YmdHis' );
		$backupFile = I ( 'post.backupfile' );
		$backupDatabase = I ( 'post.backupdatabase' );
		sleep ( 1 );
		
		$this->showMsg ( '系统原始版本:' . ONETHINK_VERSION );
		$this->showMsg ( 'OneThink在线更新日志：' );
		$this->showMsg ( '更新开始时间:' . date ( 'Y-m-d H:i:s' ) );
		sleep ( 1 );
		
		/* 建立更新文件夹 */
		$folder = $this->getUpdateFolder ();
		File::mk_dir ( $folder );
		$folder = $folder . '/' . $date;
		File::mk_dir ( $folder );
		
		// 备份重要文件
		if ($backupFile) {
			$this->showMsg ( '开始备份重要程序文件...' );
			G ( 'start1' );
			$backupallPath = $folder . '/backupall.zip';
			$zip = new \PclZip ( $backupallPath );
			$zip->create ( 'Application,ThinkPHP,.htaccess,admin.php,index.php' );
			$this->showMsg ( '成功完成重要程序备份,备份文件路径:<a href=\'' . __ROOT__ . $backupallPath . '\'>' . $backupallPath . '</a>, 耗时:' . G ( 'start1', 'stop1' ) . 's', 'success' );
		}
		
		/* 获取更新包 */
		// 获取更新包地址
		$updatedUrl = 'http://www.onethink.cn/index.php?m=home&c=check_version&a=getDownloadUrl';
		$params = array (
				'version' => ONETHINK_VERSION 
		);
		$updatedUrl = $this->getRemoteUrl ( $updatedUrl, 'post', http_build_query ( $params ) );
		if (empty ( $updatedUrl )) {
			$this->showMsg ( '未获取到更新包的下载地址', 'error' );
			exit ();
		}
		// 下载并保存
		$this->showMsg ( '开始获取远程更新包...' );
		sleep ( 1 );
		$zipPath = $folder . '/update.zip';
		$downZip = $this->getRemoteUrl ( $updatedUrl );
		if (empty ( $downZip )) {
			$this->showMsg ( '下载更新包出错，请重试！', 'error' );
			exit ();
		}
		File::write_file ( $zipPath, $downZip );
		$this->showMsg ( '获取远程更新包成功,更新包路径：<a href=\'' . __ROOT__ . ltrim ( $zipPath, '.' ) . '\'>' . $zipPath . '</a>', 'success' );
		sleep ( 1 );
		
		/* 解压缩更新包 */
		// TODO: 检查权限
		$this->showMsg ( '更新包解压缩...' );
		sleep ( 1 );
		$zip = new \PclZip ( $zipPath );
		$res = $zip->extract ( PCLZIP_OPT_PATH, './' );
		if ($res === 0) {
			$this->showMsg ( '解压缩失败：' . $zip->errorInfo ( true ) . '------更新终止', 'error' );
			exit ();
		}
		$this->showMsg ( '更新包解压缩成功', 'success' );
		sleep ( 1 );
		
		/* 更新数据库 */
		$updatesql = './update.sql';
		if (is_file ( $updatesql )) {
			$this->showMsg ( '更新数据库开始...' );
			if (file_exists ( $updatesql )) {
				$Model = M ();
				$sql = File::read_file ( $updatesql );
				$sql = str_replace ( "\r\n", "\n", $sql );
				foreach ( explode ( ";\n", trim ( $sql ) ) as $query ) {
					$Model->query ( trim ( $query ) );
				}
			}
			unlink ( $updatesql );
			$this->showMsg ( '更新数据库完毕', 'success' );
		}
		
		/* 系统版本号更新 */
		$file = File::read_file ( COMMON_PATH . 'Common/function.php' );
		$file = str_replace ( ONETHINK_VERSION, $version, $file );
		$res = File::write_file ( COMMON_PATH . 'Common/function.php', $file );
		if ($res === false) {
			$this->showMsg ( '更新系统版本号失败', 'error' );
		} else {
			$this->showMsg ( '更新系统版本号成功', 'success' );
		}
		sleep ( 1 );
		
		$this->showMsg ( '##################################################################' );
		$this->showMsg ( '在线更新全部完成，如有备份，请及时将备份文件移动至非web目录下！', 'success' );
	}
	
	/**
	 * 获取远程数据
	 * 
	 * @author huajie <banhuajie@163.com>
	 */
	private function getRemoteUrl($url = '', $method = '', $param = '') {
		$opts = array (
				CURLOPT_TIMEOUT => 20,
				CURLOPT_RETURNTRANSFER => true,
				CURLOPT_URL => $url,
				CURLOPT_USERAGENT => $_SERVER ['HTTP_USER_AGENT'] 
		);
		if ($method === 'post') {
			$opts [CURLOPT_POST] = 1;
			$opts [CURLOPT_POSTFIELDS] = $param;
		}
		
		/* 初始化并执行curl请求 */
		$ch = curl_init ();
		curl_setopt_array ( $ch, $opts );
		$data = curl_exec ( $ch );
		$error = curl_error ( $ch );
		curl_close ( $ch );
		return $data;
	}
	
	/**
	 * 实时显示提示信息
	 * 
	 * @param string $msg
	 *        	提示信息
	 * @param string $class
	 *        	输出样式（success:成功，error:失败）
	 * @author huajie <banhuajie@163.com>
	 */
	private function showMsg($msg, $class = '') {
		echo "<script type=\"text/javascript\">showmsg(\"{$msg}\",\"{$class}\")</script>";
		flush ();
		ob_flush ();
	}
	
	/**
	 * 生成更新文件夹名
	 * 
	 * @author huajie <banhuajie@163.com>
	 */
	private function getUpdateFolder() {
		$key = sha1 ( C ( 'DATA_AUTH_KEY' ) );
		return 'update_' . $key;
	}
}